admin / Strike
publicWeb-Based UK Cyber Compliance Tool with Reporting
Strike / StrikeXi v3 / backend / app / schemas.py
4924 B · main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | import uuid from datetime import date, datetime from typing import Optional from pydantic import BaseModel class Token(BaseModel): access_token: str token_type: str = "bearer" username: str role: str must_change_password: bool = False mfa_required: bool = False mfa_enabled: bool = False first_login_pending: bool = False class MfaChallenge(BaseModel): """Returned when a password is valid but a TOTP code is still required.""" mfa_required: bool = True mfa_token: str # short-lived token proving the password step passed username: str # ---------- Self-service signup ---------- class SignupCreate(BaseModel): surname: str first_name: str company_name: str email: str contact_number: str username: str password: str # ---------- User administration ---------- class UserOut(BaseModel): id: uuid.UUID username: str full_name: Optional[str] = None role: str is_active: bool must_change_password: bool mfa_enabled: bool mfa_required: bool # V2 profile / origin fields first_name: Optional[str] = None surname: Optional[str] = None company_name: Optional[str] = None email: Optional[str] = None contact_number: Optional[str] = None signup_origin: str = "admin" first_login_pending: bool = False last_login: Optional[datetime] = None created_at: datetime class Config: from_attributes = True class UserCreate(BaseModel): username: str password: str full_name: Optional[str] = None role: str = "assessor" mfa_required: bool = False must_change_password: bool = True # Optional profile fields when an admin creates an account first_name: Optional[str] = None surname: Optional[str] = None company_name: Optional[str] = None email: Optional[str] = None contact_number: Optional[str] = None class UserUpdate(BaseModel): full_name: Optional[str] = None role: Optional[str] = None is_active: Optional[bool] = None password: Optional[str] = None mfa_required: Optional[bool] = None must_change_password: Optional[bool] = None class PasswordChange(BaseModel): current_password: str new_password: str class MfaSetupOut(BaseModel): secret: str uri: str qr: str class MfaConfirm(BaseModel): code: str class AnswerOptionOut(BaseModel): id: uuid.UUID label: str score: float class Config: from_attributes = True class QuestionOut(BaseModel): id: uuid.UUID code: str text: str weight: float principle_id: str options: list[AnswerOptionOut] class Config: from_attributes = True class PrincipleOut(BaseModel): id: str objective_id: str title: str description: Optional[str] questions: list[QuestionOut] = [] class ObjectiveOut(BaseModel): id: str title: str description: Optional[str] principles: list[PrincipleOut] = [] # ---------- Frameworks (v3) ---------- class FrameworkOut(BaseModel): id: str name: str description: Optional[str] = None version: Optional[str] = None is_active: bool = True class Config: from_attributes = True class AssessmentCreate(BaseModel): organisation_name: str assessment_date: Optional[date] = None framework_id: str = "caf" class AnswerIn(BaseModel): question_id: uuid.UUID option_id: uuid.UUID class AnswersSubmit(BaseModel): answers: list[AnswerIn] class ReportMeta(BaseModel): organisation_name: Optional[str] = None assessment_date: Optional[date] = None # ---------- Evidence / notes (v3) ---------- class NoteIn(BaseModel): """Text note (assessment-level when question_id is omitted).""" content: str question_id: Optional[uuid.UUID] = None class EvidenceOut(BaseModel): id: uuid.UUID question_id: Optional[uuid.UUID] = None kind: str content: Optional[str] = None file_name: Optional[str] = None file_size: Optional[int] = None created_by: str created_at: datetime class Config: from_attributes = True # ---------- Score revisions (v3) ---------- class RevisionOut(BaseModel): id: uuid.UUID revision_no: int label: Optional[str] = None overall_score: Optional[float] = None snapshot: dict triggered_by: str created_at: datetime class Config: from_attributes = True class AssessmentOut(BaseModel): id: uuid.UUID framework_id: str = "caf" organisation_name: str assessment_date: date status: str overall_score: Optional[float] created_at: datetime class Config: from_attributes = True class AuditOut(BaseModel): id: int ts: datetime username: Optional[str] action: str detail: Optional[str] ip_address: Optional[str] class Config: from_attributes = True |